package tustiendas.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.gson.Gson;

@SuppressWarnings("serial")
public class StaticDataTipoComercioServlet extends HttpServlet {

	static DatastoreService datastore = DatastoreServiceFactory
			.getDatastoreService();

	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		process(req, res);
	}

	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		process(req, res);
		
	}

	public void doPut(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		process(req, res);
	}

	public void doDelete(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		process(req, res);
	}

	public void process(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		PrintWriter out = res.getWriter();

		String method = req.getMethod();
		String path = req.getPathInfo();

		System.out.println(req.getRequestURI() + " : [" + method + "|" + path
				+ "] ");

		if (path != null) {

			String[] pathComponents = path.split("/");
			String resource = pathComponents[1];

			System.out
					.println("Single action over resource '" + resource + "'");

			processResource(method, pathComponents[1], req, res);

		} else {
			System.out.println("Action over the list of resources");
			processResourceList(method, req, res);
		}

		out.close();
	}

	private void processResource(String method, String resource,
			HttpServletRequest req, HttpServletResponse res) throws IOException {

		if (!compruebaResource(resource)) {
			res.setStatus(res.SC_NOT_FOUND);
			return;
		}

		switch (method) {
		
		case "POST":
			res.setStatus(res.SC_METHOD_NOT_ALLOWED);
			break;

		case "PUT":
			updateTipoComercio(resource, req, res);
			break;

		case "GET":
			getTipoComercio(resource, req, res);
			break;

		case "DELETE":
			deleteTipoComercio(resource, res);
			break;
		}

	}
	
	private void updateTipoComercio(String resource, HttpServletRequest req,
			HttpServletResponse res) throws IOException {

		TipoComercio tp = extractTipoComercio(req);
		if (tp == null) {
			res.setStatus(res.SC_BAD_REQUEST);
		}
		
		boolean result = compruebaResource(resource);

		if (result) {
			Entity e = sacarEntidadTipoComercio(resource);

			// Asignamos todos los atributos de tipoComercio, al objeto DataStore
			e.setProperty("nombreTipo", tp.nombreTipo);

			datastore.delete(e.getKey());
			datastore.put(e);
		} else {
			res.setStatus(res.SC_FORBIDDEN);
		}
	}
	
	private void getTipoComercio(String resource, HttpServletRequest req,
			HttpServletResponse res) throws IOException {

		Gson gson = new Gson();

		Entity e = sacarEntidadTipoComercio(resource);

		TipoComercio tp = maquetadoTipoComercio(e);

		String jsonString = gson.toJson(tp);

		res.getWriter().println(jsonString);

	}
	
	private void deleteTipoComercio(String resource, HttpServletResponse res)
			throws IOException {

		Entity e = sacarEntidadTipoComercio(resource);
		if (e == null) {
			res.setStatus(res.SC_NOT_FOUND);
		}
		datastore.delete(e.getKey());
	}
	
	private TipoComercio extractTipoComercio(HttpServletRequest req) throws IOException {

		TipoComercio tp = null;
		Gson gson = new Gson();
		StringBuilder sb = new StringBuilder();
		BufferedReader br = req.getReader();

		String jsonString;
		while ((jsonString = br.readLine()) != null) {
			sb.append(jsonString);
		}
		jsonString = sb.toString();

		try {
			System.out.println("String to be parsed: <" + jsonString + ">");
			tp = gson.fromJson(jsonString, TipoComercio.class);
			System.out.println("Tipo Comercio extraido: " + tp + " (nombreTipo = '" + tp.nombreTipo
					+ "')");
		} catch (Exception e) {
			System.out.println("ERROR parseando Tipo Comercio: " + e.getMessage());
		}
		return tp;
	}
	
	private void processResourceList(String method, HttpServletRequest req,
			HttpServletResponse res) throws IOException {

		switch (method) {
		case "POST":
			postTipoComercio(req, res);
			break;

		case "PUT":
			res.setStatus(res.SC_METHOD_NOT_ALLOWED);
			break;

		case "GET":
			getTiposComercios(req, res);
			break;

		case "DELETE":
			deleteTiposComercios();
			break;

		}
	}
	
	private void postTipoComercio(HttpServletRequest req, HttpServletResponse res)
			throws IOException {

		TipoComercio tp = extractTipoComercio(req);
		if (tp == null) {
			res.setStatus(res.SC_BAD_REQUEST);
		}
		Entity e = maquetarEntidadTipoComercio(tp);

		if (!compruebaResource(tp.nombreTipo)){
			datastore.put(e);
		}else{
			res.setStatus(res.SC_FORBIDDEN);
		}
	}
	
	private void getTiposComercios(HttpServletRequest req, HttpServletResponse res)
			throws IOException {
		List<TipoComercio> listaTipoComercio = new LinkedList<TipoComercio>();
		Gson gson = new Gson();
		Iterator<Entity> it = sacarEntidadesTiposComercios();
		while (it.hasNext()) {
			Entity e = it.next();
			TipoComercio tp = maquetadoTipoComercio(e);
			listaTipoComercio.add(tp);	
		}
		String jsonString = gson.toJson(listaTipoComercio);

		res.getWriter().println(jsonString);
	}
	
	private void deleteTiposComercios() {
		List<Key> listaKeys = new LinkedList<Key>();
		Iterator<Entity> it = sacarEntidadesTiposComercios();
		while (it.hasNext()) {
			Entity e = it.next();
			listaKeys.add(e.getKey());
		}
		datastore.delete(listaKeys);
	}
	
	public static boolean compruebaResource(String resource) {
		boolean result = true;
		Entity e = sacarEntidadTipoComercio(resource);
		if (e == null) {
			result = false;
		}
		return result;
	}

	public static Entity sacarEntidadTipoComercio (String nombreTipo){
		Entity entidadTipoComercio;
		FilterPredicate fp = new FilterPredicate("nombreTipo",
				Query.FilterOperator.EQUAL, nombreTipo);
		Query q = new Query("tipoComercio").setFilter(fp);
		PreparedQuery pq = datastore.prepare(q);
		entidadTipoComercio = pq.asSingleEntity();
		return entidadTipoComercio;
	}

	public static Entity sacarEntidadTipoComercioKey(Key key) {
		Entity entidadTipoComercio;
		FilterPredicate filtroClave = new FilterPredicate(
				Entity.KEY_RESERVED_PROPERTY, Query.FilterOperator.EQUAL, key);
		Query q = new Query("tipoComercio").setFilter(filtroClave);
		PreparedQuery pq1 = datastore.prepare(q);
		entidadTipoComercio = pq1.asSingleEntity();
		return entidadTipoComercio;
	}
	
	public static Iterator<Entity> sacarEntidadesTiposComercios (){
		Iterator<Entity> entidadesTipoComercio;
		Query q = new Query("tipoComercio");
		PreparedQuery pq = datastore.prepare(q);
		entidadesTipoComercio = pq.asIterator();
		return entidadesTipoComercio;
	}
	
	public static TipoComercio maquetadoTipoComercio(Entity e) {

		TipoComercio tp = new TipoComercio();
		
		tp.nombreTipo = (String) e.getProperty("nombreTipo");

		return tp;
	}

	public static Entity maquetarEntidadTipoComercio(TipoComercio tp) {

		Entity e = new Entity("tipoComercio");
		e.setProperty("nombreTipo", tp.nombreTipo);

		return e;
	}

}
